Skip to content

Conversation

@donmccurdy
Copy link
Member

@donmccurdy donmccurdy commented Dec 17, 2025

Description

Summary

Enables IDEs with TypeScript language server support (such as VSCode) to infer types from JSDoc and detect type errors automatically. The PR is 'minimal' in the sense that it does not require migrating code into subpackages, and does not require replacing tsd-jsdoc. Either of those larger changes might still be preferable for other reasons, certainly. Adoption of TypeScript checks could be entirely incremental with this approach; we can turn type-checking on one file at a time.

Changes

  • Adds packages/engine/tsdoc.json, with type-checking disabled for all JS files by default. Individual JS files may opt-in to type checking with a // @ts-check comment at top of file.
  • For TypeScript to resolve type-only imports (for example, Cartesian2 uses Cartesian3 in its parameter types, but does not import the file), we use special comments like /** @import Cartesian3 from './Cartesian3.js'; */. TypeScript understands these, but JSDoc errors on them, so we update the JSDoc configuration to ignore @import tags. Huge thanks to @jjspace for this solution!
  • Configures ESLint for ES6 class conversion. Scratch variables can be used by the same class they instantiate, which is fine at runtime but needs a workaround in ESLint.
  • Configures CI to run tsc and check types, for files that we have opted in.
  • Added documentation to the coding guide (preview)

Background

Minimal subset of work from 12/16/2025 hackathon day, including work from @jjhembd, @jdehorty, @jjspace, and myself. Other tracks explored in the hackathon — including JSDoc-TS compatibility conversion with Gemini, smaller package reorganization, build system updates, documentation generation with typedoc, , etc. — are on the core-math branch. We'll likely want to use some of those results too, but this PR might be the minimum-viable starting point.

Issue number and link

Testing plan

Run npm run tsc, and observe no errors reported. Add this.x = 'hello world' to the Cartesian2 constructor, run npm run tsc again, and see expected error output:

packages/engine/Source/Core/Cartesian2.js:32:5 - error TS2322: Type 'string' is not assignable to type 'number'.

32     this.x = "hello world";
       ~~~~~~

Found 1 error in packages/engine/Source/Core/Cartesian2.js:32

The same error should appear in your editor/IDE, without explicitly running tsc, if the editor supports the TypeScript Language Server.

Author checklist

  • I have submitted a Contributor License Agreement
  • I have added my name to CONTRIBUTORS.md
  • I have updated CHANGES.md with a short summary of my change
  • I have added or updated unit tests to ensure consistent code coverage
  • I have updated the inline documentation, and included code examples where relevant
  • I have performed a self-review of my code

PR Dependency Tree

This tree was auto-generated by Charcoal

@github-actions
Copy link

Thank you for the pull request, @donmccurdy!

✅ We can confirm we have a CLA on file for you.

@donmccurdy donmccurdy changed the title Refactor/minimal tsc Minimal TypeScript+JSDoc adoption Dec 17, 2025
@donmccurdy donmccurdy changed the title Minimal TypeScript+JSDoc adoption Minimal TypeScript+JSDoc type checking Dec 17, 2025
@donmccurdy donmccurdy marked this pull request as ready for review December 17, 2025 16:43
@jjspace jjspace self-requested a review December 17, 2025 17:26
Copy link
Contributor

@jjspace jjspace left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this @donmccurdy! Overall I'm hugely in favor of this change. It should let us get more out of our intellisense and start catching some type errors even before switching fully to TS.

Can you please add a section to our documentation pages about this? Probably part of the Contribution guides, maybe the CodingGuide? I also had a few more comments to help guide what gets documented.

@donmccurdy
Copy link
Member Author

donmccurdy commented Jan 8, 2026

@jjspace I think all feedback on the PR has been addressed! Draft documentation in the coding guide:

https://github.com/CesiumGS/cesium/blob/refactor/minimal-tsc/Documentation/Contributors/CodingGuide/README.md#type-checking

I've moved the Cartesian2.js changes to a separate PR:

I also attempted a bulk conversion to ES6 classes for packages/engine/Source/Core/*.js:

That's too large to review and merge in bulk, for sure, but still it's encouraging to see tests passing after excluding a handful of files from the conversion.

@donmccurdy donmccurdy changed the title Minimal TypeScript+JSDoc type checking Types: Enable incremental JSDoc type checking Jan 8, 2026
Copy link
Contributor

@jjspace jjspace left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple quick comments on the new docs, thanks for adding those!


## Type Checking

We are incrementally adopting [type checking for JavaScript files](https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html). As of January 2026, type checks are enabled on a file-by-file basis, with `// @ts-check` annotations at the top of a file used to opt in. As adoption progresses, we expect this pattern will eventually be flipped to an opt-opt annotation instead. To see type system hints and errors in some editors or IDEs, you may need to configure or install TypeScript language server support. When in doubt, VSCode supports TypeScript language services [by default](https://code.visualstudio.com/docs/nodejs/working-with-javascript).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo

Suggested change
We are incrementally adopting [type checking for JavaScript files](https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html). As of January 2026, type checks are enabled on a file-by-file basis, with `// @ts-check` annotations at the top of a file used to opt in. As adoption progresses, we expect this pattern will eventually be flipped to an opt-opt annotation instead. To see type system hints and errors in some editors or IDEs, you may need to configure or install TypeScript language server support. When in doubt, VSCode supports TypeScript language services [by default](https://code.visualstudio.com/docs/nodejs/working-with-javascript).
We are incrementally adopting [type checking for JavaScript files](https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html). As of January 2026, type checks are enabled on a file-by-file basis, with `// @ts-check` annotations at the top of a file used to opt in. As adoption progresses, we expect this pattern will eventually be flipped to an opt-out annotation instead. To see type system hints and errors in some editors or IDEs, you may need to configure or install TypeScript language server support. When in doubt, VSCode supports TypeScript language services [by default](https://code.visualstudio.com/docs/nodejs/working-with-javascript).

Comment on lines +184 to +186
- [Type Checking JavaScript Files \| TypeScript](https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html)
- [JSDoc Reference \| TypeScript](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html)
- [JSDoc Cheatsheet and Type Safety Tricks](https://docs.joshuatz.com/cheatsheets/js/jsdoc/) by Joshua Tzucker
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to be careful about links like these. TS has sort of expanded or co-opted JSDoc for extra functionality that is not part of JSDoc itself. Our doc generation still uses pure JSDoc so we are beholden to only features it supports. The @import tag is helpful but I feel like that might be the only exception we want to make until our doc generation is updated.

For example in the TS JSDoc Reference it mentions the @staisfies tag. This is not a JSDoc tag and adding it will result in an error ERROR: The @satisfies tag is not a known tag.. I didn't test the others but I'm guessing there are other inconsistencies like this.

Also the very first recommendation in the Cheatsheet shows how to typeguard functions using @returns {value is TYPE}. This is also not recognized by JSDoc and results in an error like:

ERROR: Unable to parse a tag's type expression for source file /home/[user]/Programming/cesium/packages/engine/Source/Core/defined.js in line 28 with tag title "return" and text "{obj is Person}": Invalid type expression "obj is Person": Expected "|" but "i" found.

I bet we could make more edits to our JSDoc config/generation to adapt for more tags but I'm not sure the level of effort there. I mostly bring it up as a word of caution. Maybe all it needs is a warning that our doc gen still needs to work and to be careful. Or a comment that we need to restrict to only official JSDoc tags? Happy to discuss

```
3. **Prefer `@ts-expect-error` over `@ts-ignore`.** Sometimes a source file's types are _mostly_ consistent, but a few stubborn errors remain unsolved. These may be blocked by out-of-scope work, or may simply be unjustifiably difficult to solve in JSDoc-based types. Use `@ts-expect-error` annotations to relax the type system for specific lines. Unlike `@ts-ignore`, `@ts-expect-error` will raise errors when the line no longer contains an error, making it easier to clean up annotations later on.
4. **Prefer `unknown` or `@ts-expect-error` over `any`.** Casting types to `any` forces them to be accepted everywhere, and effectively disables all type-checking dependent on that type. This tends to propagate throughout a type system, reducing the effectiveness of type checks, and should be avoided when possible. Prefer casting to `unknown`, or using a `@ts-expect-error` annotation. For example, when defining an object with string keys, with values whose types we don't care about, prefer `Record<string, unknown>` to `Record<string, any>`.
5. **Type-only imports.** When JSDoc annotations depend on types not otherwise imported in a source file, it will be necessary to tell TypeScript where to find them. To avoid otherwise-unused imports, use type-only imports in separate one-line JSDoc comments:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The very first google search for "import type in JSDoc" points to an older syntax that still works for the TS side of things

/**
 * @typedef {import('./File1.js').MyObject1} MyObject1
 */

However this is not valid JSDoc and will break things. I think it's worth calling out here to not use this syntax and instead always rely only on the @import tag.

npx lebab packages/engine/Source/Core/Cartesian2.js \
-o packages/engine/Source/Core/Cartesian2.js --transform class
```
3. **Prefer `@ts-expect-error` over `@ts-ignore`.** Sometimes a source file's types are _mostly_ consistent, but a few stubborn errors remain unsolved. These may be blocked by out-of-scope work, or may simply be unjustifiably difficult to solve in JSDoc-based types. Use `@ts-expect-error` annotations to relax the type system for specific lines. Unlike `@ts-ignore`, `@ts-expect-error` will raise errors when the line no longer contains an error, making it easier to clean up annotations later on.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this suggestion for forward compatibility and cleanup. (a quick search led to articles that agree too)

Can we expand this to always include a reason with the disable comment?

It also could be good to look at enforcing this programmatically in eslint. We're already using typescript-eslint for Sandcastle but maybe it's easy to expand to engine files too? It looks like there's a ban-ts-comment rule for this to ban ts-ignore and require-reason for expect-error comments.

@ggetz
Copy link
Contributor

ggetz commented Jan 16, 2026

This PR is looking great to me!

While it doesn't need to hold up merging what we have here, I wonder if there are any TS best practices recommended by the Cesium ion team or the iTwin.js team—Maybe @tfili @angrycat9000 or @markschlosseratbentley could point us to any relevant guides?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants